package org.lds.logger.config.appender.async.disruptor;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.YieldingWaitStrategy;
import com.lmax.disruptor.dsl.Disruptor;
import com.lmax.disruptor.dsl.ProducerType;
import org.lds.logger.config.LifeCycle;
import org.lds.logger.config.appender.Appender;
import org.lds.logger.config.appender.async.AsyncAppenderGroup;
import org.lds.logger.event.LoggerEvent;

import java.util.List;

public class DisruptorAsyncAppenderGroup implements AsyncAppenderGroup, LifeCycle {
    private static final int DEFAULT_RING_BUFFER_SIZE = 1024 * 1024;
    private int queueSize;
    private List<Appender> asyncAppenderList;
    private Disruptor<LoggerEvent> disruptor;
    private LoggerEventProducer loggerEventProducer;

    public Disruptor<LoggerEvent> getDisruptor() {
        return disruptor;
    }

    public LoggerEventProducer getLoggerEventProducer() {
        return loggerEventProducer;
    }

    @Override
    public int getQueueSize() {
        return queueSize;
    }

    @Override
    public void setQueueSize(int queueSize) {
        this.queueSize = queueSize;
    }

    @Override
    public List<Appender> getAsyncAppenderList() {
        return asyncAppenderList;
    }

    @Override
    public void setAsyncAppenderList(List<Appender> asyncAppenderList) {
        this.asyncAppenderList = asyncAppenderList;
    }

    @Override
    public void initialize() {
        EventFactory<LoggerEvent> eventFactory = new LoggerEventFactory();
        LoggerEventThreadFactory threadFactory = new LoggerEventThreadFactory();
        int ringBufferSize = buildRingBufferSize();
        disruptor = new Disruptor(eventFactory, ringBufferSize, threadFactory,
                ProducerType.MULTI, new YieldingWaitStrategy());
        disruptor.handleEventsWith(new DefaultLoggerEventConsumer(this));
        disruptor.start();

        loggerEventProducer = new LoggerEventProducer(disruptor.getRingBuffer());
    }

    private int buildRingBufferSize() {
        try {
            if (queueSize < 1024 || queueSize > DEFAULT_RING_BUFFER_SIZE * 16) return DEFAULT_RING_BUFFER_SIZE;
            return queueSize;
        } catch (Throwable e) {
            return DEFAULT_RING_BUFFER_SIZE;
        }
    }

    @Override
    public void append(LoggerEvent loggerEvent) {
        loggerEventProducer.send(loggerEvent);
    }

}
